#include "tcpclient.h"
#include "ui_tcpclient.h"
#include <QByteArray>
#include <QDebug>
#include <QMessageBox>
#include <QHostAddress>
#include <QLineEdit>
#include "opewidget.h"
#include "privatechat.h"

TcpClient::TcpClient(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::TcpClient)
{
    ui->setupUi(this);
    resize(500,250);
    loadConfig();
    //链接服务器
    connect(&m_tcpSocket,SIGNAL(connected()),this,SLOT(showConnect()));
    connect(&m_tcpSocket,SIGNAL(readyRead()),this,SLOT(revcMsg()));

    m_tcpSocket.connectToHost(QHostAddress(m_strIP),m_usPort);//与ip端口建立链接
}

TcpClient::~TcpClient()
{
    delete ui;
}

void TcpClient::loadConfig()//添加函数定义
{
    QFile file(":/client.config");
    if(file.open(QIODevice::ReadOnly))
    {
        QByteArray baData =  file.readAll();
        QString strData = baData.toStdString().c_str();//byteArray转换成字符串
        file.close();
        strData.replace("\r\n"," ");//把\r\n替换成空格
        QStringList strList =  strData.split(" ");//切分空格
        m_strIP = strList.at(0);
        m_usPort = strList.at(1).toUShort();
        qDebug() << "ip : " << m_strIP<<" port :" << m_usPort;
    }
    else
    {
        QMessageBox::critical(this,"open config","open config error");
    }
}

TcpClient &TcpClient::getInstance()
{
    static TcpClient instance;
    return instance;
}

QTcpSocket &TcpClient::getTcpSocket()
{
    return m_tcpSocket;
}

QString TcpClient::loginName()
{
    return m_strLoginName;//私有变量通过共有接口获得
}

QString TcpClient::curPath()
{
    return m_strCurPath;
}

void TcpClient::setCurPath(QString strCurPath)
{
    m_strCurPath = strCurPath;
}

void TcpClient::showConnect()
{
    QMessageBox::information(this,"连接服务器","连接服务器成功");
}

void TcpClient::revcMsg()
{
    if(!OpeWidget::getInstance().getBook()->getDownloadStatus())
    {
        qDebug() << m_tcpSocket.bytesAvailable();//获取数据的大小，可读数据的大小
        //↓收数据
        uint uiPDULen =0;
        m_tcpSocket.read((char*)&uiPDULen,sizeof(uint));
        uint uiMsgLen = uiPDULen - sizeof(PDU);//实际消息的长度
        PDU *pdu = mkPDU(uiMsgLen);
        m_tcpSocket.read((char*)pdu + sizeof(uint),uiPDULen - sizeof(uint));
        //↑
        switch(pdu->uiMsgType)//判断消息类型，通过pdu传送过来的消息类型判断
        {
        case ENUM_MSG_TYPE_REGIST_RESPOND://如果是注册请求
        {
            if(strcmp(pdu->caData,REGIST_OK) == 0)
            {
                QMessageBox::information(this,"注册",REGIST_OK);
            }
            else if(strcmp(pdu->caData,REGIST_FAILED) == 0)
            {
                QMessageBox::warning(this,"注册",REGIST_FAILED);
            }
        }
        case ENUM_MSG_TYPE_LOGIN_RESPOND://如果是注册请求
        {
            if(strcmp(pdu->caData,LOGIN_OK) == 0)
            {
                m_strCurPath = QString("./%1").arg(m_strLoginName);//登陆的时候保存的用户名
                QMessageBox::information(this,"登录",LOGIN_OK);
                OpeWidget::getInstance().show();//通过调用获得引用，显示。如果登录过就跳转到这个界面
                this->hide();//this可写可不写
            }
            else if(strcmp(pdu->caData,LOGIN_FAILED) == 0)
            {
                QMessageBox::warning(this,"登录",LOGIN_FAILED);
            }
        }
        case ENUM_MSG_TYPE_ALLONLINE_RESPOND:
        {//服务器循环发送，客户端这里就是循环提取
            OpeWidget::getInstance().getFriend()->showAllOnlineUser(pdu);
            break;
        }
        case ENUM_MSG_TYPE_SEARCH_USR_RESPOND:
        {
            if(strcmp(SEARCH_USER_NO,pdu->caData) == 0)
            {
                QMessageBox::information(this,"搜索",QString("%1: not exist").arg(OpeWidget::getInstance().getFriend()->m_strSearchName));
            }
            else if(strcmp(SEARCH_USER_ONLINE,pdu->caData)== 0)
            {
                QMessageBox::information(this,"搜索",QString("%1: online").arg(OpeWidget::getInstance().getFriend()->m_strSearchName));
            }
            else if(strcmp(SEARCH_USER_OFFLINE,pdu->caData)== 0)
            {
                QMessageBox::information(this,"搜索",QString("%1: offline").arg(OpeWidget::getInstance().getFriend()->m_strSearchName));
            }
            break;
        }
        case ENUM_MSG_TYPE_ADD_FRIEND_REQUEST:
        {
            char caName[32]={'\0'};
            strncpy(caName,pdu->caData+32,32);
            //this就是指代的这个父窗口，第二个就是显示的内容
            int ret = QMessageBox::information(this,"添加好友",QString("%1 want to add you as friend ?").arg(caName),
                                     QMessageBox::Yes,QMessageBox::No);
            PDU *respdu = mkPDU(0);
            memcpy(respdu->caData,pdu->caData,32);
            if(ret == QMessageBox::Yes)
            {
                respdu->uiMsgType = ENUM_MSG_TYPE_ADD_FRIEND_AGREE;
            }
            else
            {
                respdu->uiMsgType = ENUM_MSG_TYPE_ADD_FRIEND_REFUSE;
            }
            m_tcpSocket.write((char*)respdu,respdu->uiPDULen);//发送给服务器
            free(respdu);
            respdu = nullptr;
            break;
        }
        case ENUM_MSG_TYPE_ADD_FRIEND_RESPOND:
        {
            QMessageBox::information(this,"添加好友",pdu->caData);//回复的信息。this，标头，数据
            break;
        }
        case ENUM_MSG_TYPE_ADD_FRIEND_AGREE:
        {
            char caPerName[32] = {'\0'};
            memcpy(caPerName,pdu->caData,32);
            QMessageBox::information(this,"添加好友",QString("添加%1好友成功").arg(caPerName));
            break;
        }
        case ENUM_MSG_TYPE_ADD_FRIEND_REFUSE:
        {
            char caPerName[32] = {'\0'};
            memcpy(caPerName,pdu->caData,32);
            QMessageBox::information(this,"添加好友",QString("添加%1好友失败").arg(caPerName));
            break;
        }
        case ENUM_MSG_TYPE_FLUSH_FRIEND_RESPOND:
        {
            //刷新到friend ，定义接口实现好友列表的刷新
            OpeWidget::getInstance().getFriend()->updateFriendList(pdu);
            break;
        }
        case ENUM_MSG_TYPE_DELETE_FRIEND_REQUEST:
        {
            char caName[32] = {'\0'};
            memcpy(caName,pdu->caData,32);
            QMessageBox::information(this,"删除好友",QString("%1 删除你作为他的好友").arg(caName));

            break;
        }
        case ENUM_MSG_TYPE_DELETE_FRIEND_RESPOND:
        {
            QMessageBox::information(this,"删除好友","删除好友成功");
            break;
        }
        case ENUM_MSG_TYPE_PRIVATE_CHAT_FRIEND_REQUEST:
        {
            if(privateChat::getInstance().isHidden())
            {//如果是隐藏的，就显示出来
               privateChat::getInstance().show();
            }
            char caSendName[32] = {'\0'};
            memcpy(caSendName,pdu->caData,32);
            QString strSendName = caSendName;
            privateChat::getInstance().setChatName(strSendName);
            privateChat::getInstance().updateMsg(pdu);

            break;
        }
        case ENUM_MSG_TYPE_GROUP_CHAT_FRIEND_REQUEST:
        {
            OpeWidget::getInstance().getFriend()->updateGroupMsg(pdu);
            break;
        }
        case ENUM_MSG_TYPE_CREATE_DIR_RESPOND:
        {
            QMessageBox::information(this,"创建文件",pdu->caData);

            break;
        }
        case ENUM_MSG_TYPE_FLUSH_FILE_RESPOND:
        {
            OpeWidget::getInstance().getBook()->updateFileList(pdu);
            QString strEnterDir = OpeWidget::getInstance().getBook()->enterDir();
            //返回的时候把enterdir清空掉
            if(!strEnterDir.isEmpty())
            {
                m_strCurPath = m_strCurPath +"/" +strEnterDir;//新的路径
                qDebug() <<"enter dir" <<m_strCurPath;
            }
            //获得输入的名字
            break;
        }
        case ENUM_MSG_TYPE_DEL_DIR_RESPOND:
        {
            QMessageBox::information(this,"删除文件夹",pdu->caData);//把cadata显示的内容放上去即可
            break;
        }
        case ENUM_MSG_TYPE_RENAME_FILE_RESPOND:
        {
            QMessageBox::information(this,"重命名文件",pdu->caData);

            break;
        }
        case ENUM_MSG_TYPE_ENTER_DIR_RESPOND:
        {
            OpeWidget::getInstance().getBook()->clearEnterDir();//清除
            QMessageBox::information(this,"进入文件夹",pdu->caData);
            break;
        }
        case ENUM_MSG_TYPE_UPLOAD_DIR_RESPOND:
        {
            QMessageBox::information(this,"上传文件",pdu->caData);
            break;
        }
        case ENUM_MSG_TYPE_DEL_FILE_RESPOND:
        {
            QMessageBox::information(this,"删除文件",pdu->caData);
            break;
        }
        case ENUM_MSG_TYPE_DOWNLOAD_FILE_RESPOND:
        {
            qDebug() << pdu->caData;
            char caFileName[32] = {'\0'};
            sscanf(pdu->caData,"%s %lld",caFileName,&(OpeWidget::getInstance().getBook()->m_iTotal));
            if(strlen(caFileName) > 0 && (OpeWidget::getInstance().getBook()->m_iTotal) > 0)//都大于0 ，表示是一个有效的数据
            {
                OpeWidget::getInstance().getBook()->setDownloadStatus(true);
                m_file.setFileName(OpeWidget::getInstance().getBook()->getSaveFilePath());
                if(!m_file.open(QIODevice::WriteOnly))
                {
                    QMessageBox::warning(this,"下载文件","获得保存文件的路径失败");
                }
            }
            break;
        }
        case ENUM_MSG_TYPE_SHARE_FILE_RESPOND:
        {
            QMessageBox::information(this,"共享文件",pdu->caData);
            break;
        }
        case ENUM_MSG_TYPE_SHARE_FILE_NOTE:
        {
            char *pPath = new char[pdu->uiMsgLen];
            memcpy(pPath,pdu->caMsg,pdu->uiMsgLen);
            char *pos = strrchr(pPath,'/');//这个函数是从后面找一个指定字符，找到就返回字符地址，没有就返回null;
            if(pos == nullptr)
            {
                pos++;
                QString strNote = QString("%1 share file->%2\n Do you accept ?").arg(pdu->caData).arg(pos);
                int ret = QMessageBox::question(this,"共享文件",strNote);
                if(QMessageBox::Yes == ret)
                {
                    PDU *respdu = mkPDU(pdu->uiMsgLen);
                    respdu->uiMsgType = ENUM_MSG_TYPE_SHARE_FILE_NOTE_RESPOND;
                    memcpy(respdu->caData,pdu->caMsg,pdu->uiMsgLen);
                    QString strName = TcpClient::getInstance().loginName();//获取到接收方的名字
                    strcpy(respdu->caData,strName.toStdString().c_str());
                    m_tcpSocket.write((char*)respdu,respdu->uiPDULen);
                }
                else
                {

                }

            }
            break;
        }
        case ENUM_MSG_TYPE_MOVE_FILE_RESPOND:
        {
            QMessageBox::information(this,"移动文件",pdu->caData);
            break;
        }
        default:
            break;
        }
        free(pdu);
        pdu = nullptr;
    }
    else//为真，处于收数据状态
    {
        QByteArray buffer = m_tcpSocket.readAll();
        m_file.write(buffer);
        Book *pBook = OpeWidget::getInstance().getBook();
        pBook->m_iReceived += buffer.size();//收到了多少数据
        if(pBook->m_iTotal == pBook->m_iReceived)
        {
            m_file.close();
            pBook->m_iTotal = 0;
            pBook->m_iReceived = 0;
            pBook->setDownloadStatus(false);
        }
        else if(pBook->m_iTotal < pBook->m_iReceived)
        {
            m_file.close();
            pBook->m_iTotal = 0;
            pBook->m_iReceived = 0;
            pBook->setDownloadStatus(false);
            QMessageBox::critical(this,"下载文件","下载文件失败");
        }
    }
}

#if 0
void TcpClient::on_send_pb_clicked()
{
    QString strMsg = ui->lineEdit->text();//读取lineEdit中的信息
    if(!strMsg.isEmpty())
    {
        //封装消息到pdu
        PDU *pdu = mkPDU(strMsg.size() + 1); // 传入一个多长的数据
        pdu->uiMsgType = 8888;
        memcpy(pdu->caMsg,strMsg.toStdString().c_str(),strMsg.size());//把要发送的数据拷贝到空间
        qDebug() << (char*)(pdu->caMsg);
        m_tcpSocket.write((char*)pdu,pdu->uiPDULen);
        free(pdu);//申请的堆区内存需要及时free
        pdu = nullptr;
    }
    else
    {
        QMessageBox::warning(this,"信息发送","发送的信息不能为空");
    }
}
#endif

void TcpClient::on_login_pb_clicked()//登录，都是需要把用户名和密码发送到服务器
{
    QString strName = ui->name_le->text();
    QString strPwd = ui->pwd_le->text();
    if(!strName.isEmpty() && !strPwd.isEmpty())
    {
       m_strLoginName = strName;
       PDU *pdu = mkPDU(0);//用户名和密码 caData足够放了，所以不需要创建申请额外的空间
       pdu->uiMsgType = ENUM_MSG_TYPE_LOGIN_REQUEST;//消息类型和注册不一样，其余相同，都是对接收的数据进行处理
       strncpy(pdu->caData,strName.toStdString().c_str(),32);//前32放用户名
       strncpy(pdu->caData+32,strPwd.toStdString().c_str(),32);//后32位放密码
       m_tcpSocket.write((char*)pdu,pdu->uiPDULen);
       free(pdu);
       pdu = nullptr;
    }
    else
    {
        QMessageBox::critical(this,"登录","登录失败:用户名或者密码为空");
    }
}



void TcpClient::on_regist_pb_clicked()//注册
{
    QString strName = ui->name_le->text();
    QString strPwd = ui->pwd_le->text();
    if(!strName.isEmpty() && !strPwd.isEmpty())
    {
       PDU *pdu = mkPDU(0);
       pdu->uiMsgType = ENUM_MSG_TYPE_REGIST_REQUEST;//消息类型，回头回传给服务器，服务器根据消息类型判断，进行switch case判断
       strncpy(pdu->caData,strName.toStdString().c_str(),32);//前32放用户名
       strncpy(pdu->caData+32,strPwd.toStdString().c_str(),32);//后32位放密码
       m_tcpSocket.write((char*)pdu,pdu->uiPDULen);
       free(pdu);
       pdu = nullptr;
    }
    else
    {
        QMessageBox::critical(this,"注册","注册失败:用户名或者密码为空");
    }
}

void TcpClient::on_cancel_pb_clicked()//注销
{

}
